package com.rowenci.iot_agriculture.util.iot;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.rowenci.iot_agriculture.IotAgricultureApplication;
import com.rowenci.iot_agriculture.bean.Worker;
import com.rowenci.iot_agriculture.bean.admin.Loginlog;
import com.rowenci.iot_agriculture.bean.iot.Com;
import com.rowenci.iot_agriculture.bean.iot.Message;
import com.rowenci.iot_agriculture.bean.iot.Rfid;
import com.rowenci.iot_agriculture.service.api.*;
import com.rowenci.iot_agriculture.service.impl.*;
import gnu.io.*;

import javax.annotation.Resource;

public class SerialUtil extends Thread implements SerialPortEventListener {

    public static CommPortIdentifier portId; // 串口通信管理类
    public static Enumeration<?> portList; // 有效连接上的端口的枚举
    public InputStream inputStream; // 从串口来的输入流
    public static OutputStream outputStream;// 向串口输出的流
    public static SerialPort serialPort; // 串口的引用
    // 堵塞队列用来存放读到的数据
    public BlockingQueue<byte[]> msgQueue = new LinkedBlockingQueue();
    //用来接收串口信息
    Com rfidCom;

    @Resource
    public static MessageService messageService = new MessageServiceImpl();
    @Resource
    public static WorkerService workerService = new WorkerServiceImpl();
    @Resource
    public static RfidService rfidService = new RfidServiceImpl();
    @Resource
    public static LoginlogService loginlogService = new LoginlogServiceImpl();
    @Resource
    public static ComService comService = new ComServiceImpl();

    @Override
    /**
     * SerialPort EventListene 的方法,持续监听端口上是否有数据流
     */
    public void serialEvent(SerialPortEvent event) {

        switch (event.getEventType()) {
            case SerialPortEvent.BI:
            case SerialPortEvent.OE:
            case SerialPortEvent.FE:
            case SerialPortEvent.PE:
            case SerialPortEvent.CD:
            case SerialPortEvent.CTS:
            case SerialPortEvent.DSR:
            case SerialPortEvent.RI:
            case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
                break;
            case SerialPortEvent.DATA_AVAILABLE:// 当有可用数据时读取数据
                byte[] readBuffer = new byte[14];
                try {
                    int numBytes = -1;
                    while (inputStream.available() > 0) {
                        numBytes = inputStream.read(readBuffer);

                        if (numBytes > 0) {
                            msgQueue.add(readBuffer);
                            readBuffer = new byte[14];// 重新构造缓冲对象，否则有可能会影响接下来接收的数据
                        } else {
                            msgQueue.add("额------没有读到数据".getBytes());
                        }
                    }
                } catch (IOException e) {
                }
                break;
        }
    }

    /**
     * 通过程序打开串口，设置监听器以及相关的参数
     *
     * @return 返回1 表示端口打开成功，返回 0表示端口打开失败
     */
    public int startComPort(Com com) {

        String com_name = com.getComName();
        int com_baudrate = com.getBaudrate();
        rfidCom = com;

        // 通过串口通信管理类获得当前连接上的串口列表
        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {

            // 获取相应串口对象
            portId = (CommPortIdentifier) portList.nextElement();

            // 获取串口的名称
            // 判断端口类型是否为串口
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                // 判断如果串口存在，就打开该串口
                if (portId.getName().equals(com_name)) {
                    try {
                        // 打开串口名字为COM_4(名字任意),延迟为2毫秒
                        serialPort = (SerialPort) portId.open(com_name, 3000);

                    } catch (PortInUseException e) {
                        e.printStackTrace();
                        closeSerial();
                        return 0;
                    }
                    // 设置当前串口的输入输出流
                    try {
                        inputStream = serialPort.getInputStream();
                        outputStream = serialPort.getOutputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                        return 0;
                    }
                    // 给当前串口添加一个监听器
                    try {
                        serialPort.addEventListener(this);
                    } catch (TooManyListenersException e) {
                        e.printStackTrace();
                        return 0;
                    }
                    // 设置监听器生效，即：当有数据时通知
                    serialPort.notifyOnDataAvailable(true);

                    // 设置串口的一些读写参数
                    try {
                        // 比特率、数据位、停止位、奇偶校验位
                        serialPort.setSerialPortParams(com_baudrate,
                                SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                                SerialPort.PARITY_NONE);
                    } catch (UnsupportedCommOperationException e) {
                        e.printStackTrace();
                        return 0;
                    }

                    return 1;
                }
            }
        }
        return 0;

    }

    public void closeSerial() {
        serialPort.close();
    }

    /**
     * 16进制字符串转字节数组
     * 用来发数据
     *
     * @param hexString
     * @return
     */
    public static byte[] hexStrToBinaryStr(String hexString) {


        if (hexString.isEmpty()) {
            return null;
        }

        hexString = hexString.replaceAll(" ", "");

        int len = hexString.length();
        int index = 0;


        byte[] bytes = new byte[len / 2];

        while (index < len) {

            String sub = hexString.substring(index, index + 2);

            bytes[index / 2] = (byte) Integer.parseInt(sub, 16);

            index += 2;
        }


        return bytes;
    }


    /**
     * 数组转换成十六进制字符串
     * 用来收数据
     *
     * @return HexString
     */
    public static final String bytesToHexString(byte[] bArray) {
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    @Override
    public void run() {
        try {
            while (IotAgricultureApplication.state == true){
                Com com_state = comService.findComById(rfidCom.getId());
                if (com_state == null){
                    closeSerial();
                    return;
                }
                // 如果堵塞队列中存在数据就将其输出
                if (msgQueue.size() > 0) {
                    //取出数据
                    Message message = new Message();
                    Com com = comService.findComById(rfidCom.getId());
                    System.out.println(com);
                    //数据
                    String str = bytesToHexString(msgQueue.take());
                    System.out.println("卡号:" + str);
                    message.setComId(com.getId());
                    message.setInfo(str);
                    /**
                     * 下面是登录记录
                     * loginlog
                     */
                    //卡号
                    String rfid_id = str.substring(0, 10);
                    //日期
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String time = df.format(new Date());
                    //大棚id
                    Integer house_id = com.getHouseId();

                    //worker_id
                    Rfid rfid = rfidService.findByCarNumber(rfid_id);
                    Worker worker = workerService.findByRfid_id(rfid.getId());
                    if (worker.getId() != null) {
                        //卡号存在时
                        //初始化loginlog对象
                        Loginlog loginlog = new Loginlog();
                        loginlog.setWorker_id(worker.getId());
                        loginlog.setRfid_id(rfid.getId());
                        loginlog.setGreenhouse_id(house_id);
                        loginlog.setTime(time);
                        //添加记录
                        loginlogService.addLog(loginlog);
                        messageService.updateMessage(message);

                        //向步进电机发送数据
                        //获取步进电机串口
                        Com walkerCom = comService.findComByHouse_idAndSensor(house_id, "walker");
                        SerialUtil serial = new SerialUtil();
                        int code = serial.startComPort(walkerCom);
                        if (code == 1) {
                            //串口打开成功
                            System.out.println("步进电机打开成功:" + walkerCom.getComName());
                            try {
                                byte[] st = serial.hexStrToBinaryStr("EECC1001010000000000000000FF");
                                outputStream.write(st, 0, st.length);
                                serial.closeSerial();
                            } catch (IOException e) {
                                serial.closeSerial();
                                e.printStackTrace();
                            }
                        }

                    } else {
                        //卡号不存在时向警报器发送数据
                        //获取警报器串口
                        Com alarmCom = comService.findComByHouse_idAndSensor(house_id, "alarm");
                        //响
                        SerialUtil serial1 = new SerialUtil();
                        int code1 = serial1.startComPort(alarmCom);
                        if (code1 == 1) {
                            //串口打开成功
                            System.out.println("警报器打开成功:" + com.getComName());
                            try {
                                byte[] st = serial1.hexStrToBinaryStr("EECC0E01010000000000010000FF");
                                System.out.println("发出字节数：" + st.length + "开始报警");
                                outputStream.write(st, 0, st.length);
                                serial1.closeSerial();
                            } catch (IOException e) {
                                serial1.closeSerial();
                                e.printStackTrace();
                            }
                        }
                        System.out.println("卡号不存在");

                        Thread.sleep(2000);

                        //不响
                        SerialUtil serial2 = new SerialUtil();
                        int code2 = serial2.startComPort(alarmCom);
                        if (code2 == 1) {
                            //串口打开成功
                            System.out.println("警报器打开成功:" + com.getComName());
                            try {
                                byte[] st = serial2.hexStrToBinaryStr("EECC0E01010000000000000000FF");
                                System.out.println("发出字节数：" + st.length + "停止报警");
                                outputStream.write(st, 0, st.length);
                                serial2.closeSerial();
                            } catch (IOException e) {
                                serial2.closeSerial();
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            while (IotAgricultureApplication.state == false){
                closeSerial();
                IotAgricultureApplication.state = true;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

